﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Web;
using System.IO;
using System.Windows.Forms;

namespace SZJT.Framework.Adapter
{
    public static class AdapterFactory
    {
        private static readonly object Lock = new object();
        private static Dictionary<string, IAdapter> _adapters;
        private static DateTime? _lastEditTime;
        private static string _taskListStr = string.Empty;
        public static string TaskListStr { get { return _taskListStr; } }
        public static string ConfigPath{ get; set; }

        public static IAdapter GetAdapter(string taskGuid)
        {
            try
            {
                if (ComponentIsChanged())
                {
                    _adapters = null;
                    _taskListStr = string.Empty;
                }
                   
                if (_adapters == null || _adapters.Count == 0)
                {
                    lock (Lock)
                    {
                        if (_adapters == null || _adapters.Count == 0)
                        {
                            _adapters = new Dictionary<string, IAdapter>();
                            var compConfig = new ComponentConfiguration(ConfigPath);
                            var component = compConfig.GetComponent();
                            foreach (var adapter in component.Adapters)
                            {
                                var T = Type.GetType(adapter.Type);
                                var adapterEntity = (IAdapter)Activator.CreateInstance(T);
                                XmlNode param;
                                switch(adapterEntity.Category)
                                {
                                    case Constants.ACCOUNT_ADAPTER:
                                        param = GetAccountParam(component.AccountName, component.Password, adapter.Protocol);
                                        break;
                                    case Constants.CERT_ADAPTER:
                                        param=GetCertificateParam(component.AccountName, adapter.Protocol, component.CertName);
                                        break;
                                    default:
                                        param = GetPublicParam(adapter.Guid, adapter.Protocol, adapter.TaskList);
                                        break;
                                }
                                if (adapterEntity.SetData(Constants.ORG_GUID, Constants.INIT_GUID, Constants.INIT_TYPE, param) != 0)
                                    throw new Exception("设置适配器映射时发生异常");
                                var taskList = adapterEntity.TaskListString.Split(',');
                                _taskListStr += adapterEntity.TaskListString + ",";
                                _adapters.Add(adapter.Guid, adapterEntity);
                                foreach (var item in taskList)
                                    if (!_adapters.ContainsKey(item))
                                        _adapters.Add(item, adapterEntity);
                            }
                            _taskListStr.Trim(',');
                        }
                    }
                }
                if (_adapters.ContainsKey(taskGuid))
                    return _adapters[taskGuid];
                return null;
            }
            catch (Exception e)
            {
                LoggerHelper.WriteCodePointInfo(e.Message);
                LoggerHelper.WriteStackTraceInfo(e.StackTrace);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="param"></param>
        /// <param name="adapter"></param>
        /// <returns></returns>
        public static bool InitAdapter(XmlNode param,IAdapter adapter)
        {
            return adapter.SetData(Constants.ORG_GUID, Constants.INIT_GUID, Constants.INIT_TYPE, param) == 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="pwd"></param>
        /// <param name="protocol"></param>
        /// <returns></returns>
        public static XmlNode GetAccountParam(string userName,string pwd,string protocol)
        {
            var xmlDoc = new XmlDocument();
            var sb = new StringBuilder();
            sb.Append(string.Format("<Document TaskGuid=\"{0}\" DataGuid=\"{1}\" DataType=\"{2}\">", Constants.ORG_GUID,Constants.INIT_GUID,Constants.INIT_TYPE));
            sb.Append(string.Format("<UserName Type=\"TEXT\">{0}</UserName>", userName));
            sb.Append(string.Format("<Password Type=\"TEXT\">{0}</Password>", pwd));
            sb.Append(string.Format("<Protocol Type=\"TEXT\">{0}</Protocol>", protocol));
            sb.Append("</Document>");
            xmlDoc.LoadXml(sb.ToString());
            return xmlDoc.DocumentElement;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="protocol"></param>
        /// <param name="findValue"></param>
        /// <returns></returns>
        public static XmlNode GetCertificateParam(string userName, string protocol, string findValue)
        {
            var config = new ComponentConfiguration();
            var component = config.GetComponent();
            var cert = config.GetCert(component.CertName);
            if(null==cert)
            {
                throw new Exception("组件未配置证书信息");
            }
            var xmlDoc = new XmlDocument();
            var sb = new StringBuilder();
            sb.Append(string.Format("<Document TaskGuid=\"{0}\" DataGuid=\"{1}\" DataType=\"{2}\">", Constants.ORG_GUID, Constants.INIT_GUID, Constants.INIT_TYPE));
            sb.Append(string.Format("<UserName Type=\"TEXT\">{0}</UserName>", userName));
            sb.Append("<Certificate Type=\"TEXT\">");
            sb.Append(string.Format("<StoreLocation Type=\"TEXT\">{0}</StoreLocation>",
                                    string.IsNullOrEmpty(cert.StoreLocation)
                                        ? Constants.STORE_LOCATION 
                                        : cert.StoreLocation));
            sb.Append(string.Format("<StoreName Type=\"TEXT\">{0}</StoreName>",
                                    string.IsNullOrEmpty(cert.StoreName) 
                                        ? Constants.STORE_NAME 
                                        : cert.StoreName));
            sb.Append(string.Format("<FindValue Type=\"TEXT\">{0}</FindValue>", cert.FindValue));
            sb.Append(string.Format("<FindType Type=\"TEXT\">{0}</FindType>",
                                    string.IsNullOrEmpty(cert.FindType) 
                                        ? Constants.FIND_TYPE 
                                        : cert.FindType));
            sb.Append("</Certificate>");
            sb.Append(string.Format("<Protocol Type=\"TEXT\">{0}</Protocol>", protocol));
            sb.Append("</Document>");
            xmlDoc.LoadXml(sb.ToString());
            return xmlDoc.DocumentElement;
        }

        public static XmlNode GetPublicParam(string userID, string protocol, string taskList)
        {   
            var xmlDoc = new XmlDocument();
            var sb = new StringBuilder();
            sb.Append(string.Format("<Document TaskGuid=\"{0}\" DataGuid=\"{1}\" DataType=\"{2}\">", Constants.ORG_GUID, Constants.INIT_GUID, Constants.INIT_TYPE));
            sb.Append(string.Format("<UserID Type=\"TEXT\">{0}</UserID>", userID));
            sb.Append(string.Format("<Protocol Type=\"TEXT\">{0}</Protocol>", protocol));
            sb.Append(string.Format("<TaskList Type=\"TEXT\">{0}</TaskList>", taskList));
            sb.Append("</Document>");
            xmlDoc.LoadXml(sb.ToString());
            return xmlDoc.DocumentElement;
        }

        /// <summary>
        /// Component.xml最后修改日期
        /// </summary>
        /// <returns></returns>
        public static DateTime? GetLastModifyDate()
        {
            string path;
            try
            {
                if (null == HttpContext.Current)
                {
                    var di = new DirectoryInfo(Application.StartupPath);
                    path = di.Parent.Parent.FullName + "\\Configs\\Component.xml";
                }
                else
                    path = HttpContext.Current.Server.MapPath("~/Configs/Component.xml");
                if (string.IsNullOrEmpty(path))
                    return null;
                if (!File.Exists(path))
                    return null;
                return File.GetLastWriteTime(path);
            }
            catch
            {
                return DateTime.Now;
            }
        }
        /// <summary>
        /// 检查组件配置是否被修改过
        /// </summary>
        /// <returns>是代表与修改</returns>
        private static bool ComponentIsChanged()
        {
            var lastTime = GetLastModifyDate();
            if (_lastEditTime != lastTime)
            {
                _lastEditTime = lastTime;
                return true;
            }
            return false;
        }
       
    }
}
